/*
	This file is part of Lproxy.

    Lproxy is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Lproxy is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Lproxy.  If not, see <http://www.gnu.org/licenses/>.
*/
package lproxy_client;

import java.net.*;
import java.util.*;
import java.util.Map.*;
import java.io.*;

public class ProxyClient
{
	public ProxyClient()
	{
		ProxyClient.m_path = Lproxy_client.class.getProtectionDomain().getCodeSource().getLocation().getFile();
		if(ProxyClient.m_path.endsWith("/") == false)
		{
			ProxyClient.m_path = ProxyClient.m_path.substring(0,ProxyClient.m_path.lastIndexOf("/")+1);
		}
		else
		{
			ProxyClient.m_path += "lproxy_client/";
		}
		try
		{
			Setting();
		}
		catch(Exception e)
		{
			System.out.println("Open config file error " + e.toString());
		}
		try
		{
			this.m_socket = new ServerSocket(Integer.parseInt(this.m_port));
			this.m_socket.setSoTimeout(0);
		}
		catch(Exception e)
		{
			ProxyClient.PrintMessage(e.toString());
		}
	}
	public void start()
	{
		try {
			if(!TestServer())
			{
				ProxyClient.PrintMessage("Couldn't link to server");
				return;
			}
		}
		catch(Exception e)
		{
			ProxyClient.PrintMessage(e.toString());
		}
		ProxyClient.PrintMessage("Server start");
		while(true)
		{
			try
			{
				new ServerThread(this.m_socket.accept(),this).start();
			}
			catch(Exception e)
			{
				ProxyClient.PrintMessage(e.toString());
			}
		}
	}
	public static void PrintMessage(String p_message)
	{
		System.out.println(p_message);
	}
	private boolean TestServer() throws Exception
	{
		HttpURLConnection conn;
		conn = (HttpURLConnection)new URL(this.m_server_address + "?test=true").openConnection();
		conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
		conn.setRequestMethod("GET");
		conn.setDoOutput(true);
		conn.connect();
		InputStream in = conn.getInputStream();
		byte[] r = new byte[64];
		while(in.read(r,0,64) != -1);
		String data = new String(r);
		int begin,end;
		begin = data.indexOf("-B-");
		end = data.indexOf("-E-");
		String temp = data.substring(begin + "-B-".length(),end);
		data = new String(LCoder.decode(temp));
		if(data.startsWith("OK"))
			return true;
		else 
			return false;
	}
	private void Setting() throws Exception
	{
		ProxyClient.PrintMessage("Current directory : " + ProxyClient.m_path);
		//Read Settings
		File f = new File(ProxyClient.m_path + ProxyClient.CONFIG_PATH);
		BufferedReader reader = new BufferedReader(new FileReader(f));
		Map<String,String> config = new HashMap<String,String>();
		String line;
		while((line=reader.readLine())!=null)
		{
			if(line.startsWith("#") || line.equals(""))
				continue;
			String[] temp = line.split("=",2);
			config.put(temp[0],temp[1]);
		}
		if(config.isEmpty())
		{
			throw new Exception("Config is empty");
		}
		this.m_server_address = config.get("server_address");
		this.m_port = config.get("port");
		Iterator<Entry<String,String>> i = config.entrySet().iterator();
		while(i.hasNext())
		{
			Entry<String,String> b = i.next();
			ProxyClient.PrintMessage("Set " + b.getKey() + " : " + b.getValue());
		}
	}
	String GetServerAddress()
	{
		return this.m_server_address;
	}
	private final static String CONFIG_PATH = "config.conf";
	private String m_server_address;
	private String m_port = "9090";
	private ServerSocket m_socket;
	private static String m_path;
	public static volatile int threadcount = 0;
}

class ServerThread extends Thread
{
	ServerThread (Socket p_socket,ProxyClient p_client) throws Exception
	{
		this.server_address = p_client.GetServerAddress();
		this.m_socket = p_socket;
		this.m_cc = new ConnectClient(this.m_socket);
		this.m_cs = new ConnectServer(this.server_address,this.m_cc);
	}
	public void run()
	{
		ProxyClient.threadcount++;
		ProxyClient.PrintMessage("A client linked.Thread count:" + ProxyClient.threadcount);
		String source = null;
		try
		{
			source = this.m_cc.Receive();
		}
		catch(Exception e)
		{
			ProxyClient.PrintMessage("Error at ConnectClient Receive() " + e.toString());
		}
		try
		{
			this.m_cs.Send(source);
		}
		catch(Exception e)
		{
			ProxyClient.PrintMessage("Error at ConnectServer Send() " + e.toString());
		}
		try
		{
			this.m_cs.ReceiveAndSend();
		}
		catch(Exception e)
		{
			ProxyClient.PrintMessage("Error at ConnectServer ReceiveAndSend() " + e.toString());
		}
		ProxyClient.threadcount--;
		ProxyClient.PrintMessage("A client dislinked.Thread count:" + ProxyClient.threadcount);
	}
	ConnectServer m_cs;
	ConnectClient m_cc;
	private String server_address;
	private Socket m_socket;
}
